/** =====================================================
 * Copyright © hk. 2022-2025. All rights reserved.
 * File name  : main.c
 * Author     : 苏木
 * Date       : 2024-08-12
 * Version    : 
 * Description: 
 * ======================================================
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "./aes_core.h"
#include "./wave.h"

#define USER_AES_KEY     "sumu"
#define USER_AES_KEY_LEN (128)
#define AUDIO_FRAME_LEN  (1280)
#define FILE_OFFSET      (44)

typedef struct __user_aes_key
{
    /* data */
    unsigned char user_key[32];
    unsigned int  user_key_len;
}user_aes_key;

unsigned char audio_buff[AUDIO_FRAME_LEN * 1280] = {0};
user_aes_key aes_key_info = {0};
WAVE_HEADER wav_header = {0};

extern char *optarg;
extern int optind, opterr, optopt;

int usage_info(void)
{
    printf("\n========================================\n");
    printf("help info:\n");
    printf("./app -t aes_type -f file_name\n");
    printf("\n");
    printf("aes_type : 0, AES_DECRYPT; 1, AES_ENCRYPT\n");
    printf("file_name: < 63 Bytes\n");
    printf("========================================\n");

    return 0;
}

int wav_info(WAVE_HEADER * head_info)
{
    if(head_info == NULL)
    {
        printf("[error]wav head info is NULL\n");
        return -1;
    }
    printf("===========================\n");
    printf("WAV header information:\n");
    printf("ChunkID \t%c%c%c%c\n", head_info->riff.ChunkID[0], head_info->riff.ChunkID[1], head_info->riff.ChunkID[2], head_info->riff.ChunkID[3]);
    printf("ChunkSize \t%d\n", head_info->riff.ChunkSize);
    printf("Format \t\t%c%c%c%c\n", head_info->riff.Format[0], head_info->riff.Format[1], head_info->riff.Format[2], head_info->riff.Format[3]);
    printf("\n");

    printf("Subchunk1ID \t%c%c%c%c\n", head_info->fmt.Subchunk1ID[0], head_info->fmt.Subchunk1ID[1], head_info->fmt.Subchunk1ID[2], head_info->fmt.Subchunk1ID[3]);
    printf("Subchunk1Size \t%d\n", head_info->fmt.Subchunk1Size);
    printf("AudioFormat \t%d\n", head_info->fmt.AudioFormat);
    printf("NumChannels \t%d\n", head_info->fmt.NumChannels);
    printf("SampleRate \t%d\n", head_info->fmt.SampleRate);
    printf("ByteRate \t%d\n", head_info->fmt.ByteRate);
    printf("BlockAlign \t%d\n", head_info->fmt.BlockAlign);
    printf("BitsPerSample \t%d\n", head_info->fmt.BitsPerSample);
    printf("\n");

    printf("blockID \t%c%c%c%c\n", head_info->data.Subchunk2ID[0], head_info->data.Subchunk2ID[1], head_info->data.Subchunk2ID[2], head_info->data.Subchunk2ID[3]);
    printf("blockSize \t%d\n", head_info->data.Subchunk2Size);
    printf("\n");
    //duration = Subchunk2Size / ByteRate
    printf("duration \t%d\n",  head_info->data.Subchunk2Size /  head_info->fmt.ByteRate);
    printf("===========================\n");
    return 0;
}

int main(int argc, char *argv[])
{
    /* code */
    int ret = 0;
    int i = 0;
    FILE *fp_src = NULL;
    FILE *fp_dst = NULL;

    unsigned int src_file_size = 0;
    char file_name[64] = {0};

    int aes_type = -1;
    printf("\n***[%s][%d] Build Time : [%s %s], Git version:%s remote: %s ***\n\n",
            __func__, __LINE__,__DATE__, __TIME__, GIT_VERSION, GIT_PATH);

    // 参数数量校验
    if(argc < 2)
    {
        ret = usage_info();
        if(ret != 0)
        {
            printf("[error]usage_info fail!ret=%d\n", ret);
        }
        return -1;
    }
    // 打印main函数参数
    printf("argc=%d,argv[]=", argc);
    for(i = 0; i < argc; i++)
    {
        printf("%s ", argv[i]);
    }
    printf("\n");
    // 参数解析
    int opt = 0;
    int opt_arg = 0;
    char *opt_string = NULL;
    while ((opt = getopt(argc, argv, "t:f:")) != -1) 
    {
        switch (opt) 
        {
            case 't':
                opt_arg = atoi(optarg);
                break;
            case 'f':
                opt_string = optarg;
                break;
            default: /* '?' */
                usage_info();
                exit(EXIT_FAILURE);
        }
    }
    //参数赋值
    switch(opt_arg)
    {
        case 0:
            aes_type = AES_DECRYPT;
            break;
        case 1:
            aes_type = AES_ENCRYPT;
            break;
        default:
            printf("[error]not support!\n");
            exit(EXIT_FAILURE);
    }
    if(opt_string == NULL || strlen(opt_string) > 63)
    {
        printf("[error]file name is NULL or too long(> 63Byte))!\n");
        exit(EXIT_FAILURE);
    }
    // 设置aes解密密钥
    snprintf((char *)aes_key_info.user_key, sizeof(aes_key_info.user_key), "%s", USER_AES_KEY);
    aes_key_info.user_key_len = USER_AES_KEY_LEN;
    printf("aes_key_info user_key=%s len=%d,aes_type=%d file_name=%s\n", 
            aes_key_info.user_key, aes_key_info.user_key_len,
            aes_type, opt_string);
    printf("get aes key char is:");
    for (i = 0; i < sizeof(aes_key_info.user_key); i++)
    {
        /* code */
        if(aes_key_info.user_key[i] != '\0')
        {
            printf("%c-0x%x ", aes_key_info.user_key[i], aes_key_info.user_key[i]);
        }
    }
    printf("\n");
    func_aes_secret_key_config(aes_key_info.user_key, aes_key_info.user_key_len, aes_type);

    // 打开加密文件
    snprintf(file_name, sizeof(file_name), "%s", opt_string);
    fp_src = fopen(file_name, "ab+");
    if(fp_src == NULL)
    {
        printf("%s open failed!\n", file_name);
        return -1;
    }
    fseek(fp_src, 0, SEEK_END);
    src_file_size = ftell(fp_src);
    fseek(fp_src, 0, SEEK_SET);
    ret = fread(&wav_header, 1, sizeof(wav_header), fp_src);
    if(ret < sizeof(WAVE_HEADER))
    {
        printf("[error]%s wav header read fail!ret=%d\n", file_name, ret);
        return -1;
    }
    printf("file %s size is %d, now fp pointer is in %ld\n", file_name, src_file_size, ftell(fp_src));
    
    ret = wav_info(&wav_header);
    if(ret < 0)
    {
        printf("[error]%s wav header read fail!ret=%d\n", file_name, ret);
        return -1;
    }
    char *dst_file_type = (aes_type == AES_DECRYPT)?"decrypt":"encrypt";
    snprintf(file_name, sizeof(file_name), "%s_%s", dst_file_type, opt_string);
    fp_dst = fopen(file_name, "w");
    if(fp_dst == NULL)
    {
        printf("%s open failed!\n", file_name);
        return -1;
    }
    fwrite(&wav_header, 1, sizeof(WAVE_HEADER), fp_dst);

    while (1)
    {
        /* code */
        ret = fread(audio_buff, 1, AUDIO_FRAME_LEN, fp_src);
        if(ret < AUDIO_FRAME_LEN)
        {
            printf("audio frame read end!ret=%d\n", ret);
            break;
        }
        // 加密或者解密
        switch(aes_type)
        {
            case AES_DECRYPT:
                func_aes_decrypt_pack(NULL, audio_buff, AUDIO_FRAME_LEN);
                break;
            case AES_ENCRYPT:
                func_aes_encrypt_pack(NULL, audio_buff, AUDIO_FRAME_LEN);
                break;
            default:
                printf("[error]not support!\n");
                break;
        }
        fwrite(audio_buff, 1, AUDIO_FRAME_LEN, fp_dst);

    }

    fclose(fp_src);
    fclose(fp_dst);
    
    return 0;
}

